package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.srb.core.enums.LendStatusEnum;
import com.atguigu.srb.core.enums.ReturnMethodEnum;
import com.atguigu.srb.core.enums.TransTypeEnum;
import com.atguigu.srb.core.hfb.HfbConst;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.mapper.*;
import com.atguigu.srb.core.pojo.bo.TransFlowBO;
import com.atguigu.srb.core.pojo.entity.*;
import com.atguigu.srb.core.pojo.vo.BorrowInfoApprovalVO;
import com.atguigu.srb.core.pojo.vo.BorrowerDetailVO;
import com.atguigu.srb.core.service.*;
import com.atguigu.srb.core.util.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标的准备表 服务实现类
 * </p>
 *
 * @author fun
 * @since 2021-10-29
 */
@Service
public class LendServiceImpl extends ServiceImpl<LendMapper, Lend> implements LendService {
    @Autowired
    DictService dictService;

    @Autowired
    BorrowerMapper borrowerMapper;
    @Autowired
    BorrowerService borrowerService;
    @Autowired
    UserAccountMapper userAccountMapper;
    @Autowired
    UserInfoMapper userInfoMapper;
    @Autowired
    UserInfoService userInfoService;
    @Autowired
    TransFlowService transFlowService;
    @Autowired
    LendItemMapper lendItemMapper;
    @Autowired
    LendReturnMapper lendReturnMapper;
    @Autowired
    LendItemReturnMapper lendItemReturnMapper;

    @Override
    public void creatLend(BorrowInfoApprovalVO borrowInfoApprovalVO, BorrowInfo borrowInfoParam) {
        //生成标的信息
        System.out.println("由借款审核生成标的信息");
        Lend lend = new Lend();

        lend.setUserId(borrowInfoParam.getUserId());
        lend.setBorrowInfoId(borrowInfoParam.getId());
        lend.setLendNo(LendNoUtils.getLendNo());//生成编号
        lend.setTitle(borrowInfoApprovalVO.getTitle());// 标的名称
        lend.setAmount(borrowInfoParam.getAmount());// 借款总金额
        lend.setPeriod(borrowInfoParam.getPeriod());// 投资期数
        lend.setLendYearRate(borrowInfoApprovalVO.getLendYearRate().divide(new BigDecimal(100)));//从审批对象中获取
        lend.setServiceRate(borrowInfoApprovalVO.getServiceRate().divide(new BigDecimal(100)));//从审批对象中获取
        lend.setReturnMethod(borrowInfoParam.getReturnMethod());
        lend.setLowestAmount(new BigDecimal(100));// 最低投资金额
        lend.setInvestAmount(new BigDecimal(0));// 目前已投金额
        lend.setInvestNum(0);// 投资人数
        lend.setPublishDate(LocalDateTime.now());// 标的生成时间

        //起息日期
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate lendStartDate = LocalDate.parse(borrowInfoApprovalVO.getLendStartDate(), dtf);
        lend.setLendStartDate(lendStartDate);
        //结束日期
        LocalDate lendEndDate = lendStartDate.plusMonths(borrowInfoParam.getPeriod());//c.add(Calendar.MONTH,3);
        lend.setLendEndDate(lendEndDate);
        lend.setLendInfo(borrowInfoApprovalVO.getLendInfo());//描述

        //平台预期收益
        //        月年化 = 年化 / 12
        BigDecimal monthRate = lend.getServiceRate().divide(new BigDecimal(12), 8, BigDecimal.ROUND_HALF_DOWN);// 平台的月服务费率
        //        平台收益 = 标的金额 * 月年化 * 期数
        BigDecimal expectAmount = lend.getAmount().multiply(monthRate).multiply(new BigDecimal(lend.getPeriod()));// 平台预期收益
        lend.setExpectAmount(expectAmount);

        //实际收益
        lend.setRealAmount(new BigDecimal(0));
        //状态
        lend.setStatus(LendStatusEnum.INVEST_RUN.getStatus());
        //审核时间
        lend.setCheckTime(LocalDateTime.now());
        //审核人
        lend.setCheckAdminId(1L);

        baseMapper.insert(lend);
    }

    @Override
    public List<Lend> getList() {
        List<Lend> lends = baseMapper.selectList(null);
        for (Lend lend : lends) {
            Map<String, Object> map = new HashMap<>();
            map.put("returnMethod", dictService.getNameByParentDictCodeAndValue("returnMethod", lend.getReturnMethod()));
            map.put("status", LendStatusEnum.getMsgByStatus(lend.getStatus()));
            lend.setParam(map);
        }
        return lends;
    }

    @Override
    public Map<String, Object> show(Long id) {
        Lend lend = baseMapper.selectById(id);
        Map<String, Object> param = new HashMap<>();
        param.put("returnMethod", dictService.getNameByParentDictCodeAndValue("returnMethod", lend.getReturnMethod()));
        param.put("status", LendStatusEnum.getMsgByStatus(lend.getStatus()));
        lend.setParam(param);

        // 借款人信息
        Long userId = lend.getUserId();
        QueryWrapper<Borrower> borrowerQueryWrapper = new QueryWrapper<>();
        borrowerQueryWrapper.eq("user_id", userId);
        Borrower borrower = borrowerMapper.selectOne(borrowerQueryWrapper);
        //组装借款人对象
        BorrowerDetailVO show = borrowerService.getBorrowerDetailVOById(borrower.getId());

        // 返回结果
        Map<String, Object> map = new HashMap<>();
        map.put("lend", lend);
        map.put("borrower", show);

        return map;
    }

    @Override
    public BigDecimal getInterestCount(BigDecimal investAmount, BigDecimal lendYearRate, BigDecimal period, BigDecimal returnMethod) {
        BigDecimal interestCount = new BigDecimal("0");
        //计算收益
        if (returnMethod.intValue() == ReturnMethodEnum.ONE.getMethod()) {
            interestCount = Amount1Helper.getInterestCount(investAmount, lendYearRate, period.intValue());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.TWO.getMethod()) {
            interestCount = Amount2Helper.getInterestCount(investAmount, lendYearRate, period.intValue());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.THREE.getMethod()) {
            interestCount = Amount3Helper.getInterestCount(investAmount, lendYearRate, period.intValue());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.FOUR.getMethod()) {
            interestCount = Amount4Helper.getInterestCount(investAmount, lendYearRate, period.intValue());
        }
        return interestCount;
    }

    @Override
    public void makeLoan(Long id) {
        System.out.println("放款业务");

        // 查询标的信息
        System.out.println("查询标的");
        Lend lend = new Lend();
        lend = baseMapper.selectById(id);

        // 根据标的信息调用汇付宝放款接口
        System.out.println("调用汇付宝放款接口");
        Map<String, Object> paramMap = new HashMap<>();
        //封装参数
        paramMap = putParams(lend);
        String url = HfbConst.MAKE_LOAD_URL;
        JSONObject jsonObject = RequestHelper.sendRequest(paramMap, url);
        String resultCode = jsonObject.getString("resultCode");
        if ("0000".equals(resultCode)) {
            // 汇付宝接口返回结果成功，修改标的状态
            System.out.println("汇付宝调用完成，修改标的状态");
            lend.setRealAmount(new BigDecimal("0"));
            lend.setPaymentAdminId(1L);
            lend.setPaymentTime(LocalDateTime.now());
            lend.setStatus(LendStatusEnum.PAY_RUN.getStatus());
            baseMapper.updateById(lend);

            // 借款人账户，交易流水
            System.out.println("借款人账户更新");
            Long borrowerUserId = lend.getUserId();
            BigDecimal voteAmt = jsonObject.getBigDecimal("voteAmt");
            String agentBillNo = jsonObject.getString("agentBillNo");
            String borrowerbindCode = userInfoService.getBindCodeById(borrowerUserId);
            userAccountMapper.updateAccount(borrowerbindCode, new BigDecimal("0"), voteAmt);
            transFlowService.saveTransFlow(new TransFlowBO(agentBillNo, borrowerbindCode, voteAmt, TransTypeEnum.BORROW_BACK, "放款到账"));

            // 投资人(集合)账户，交易流水
            System.out.println("投资人账户更新");
            QueryWrapper<LendItem> lendItemQueryWrapper = new QueryWrapper<>();
            lendItemQueryWrapper.eq("lend_id", id);
            List<LendItem> lendItems = lendItemMapper.selectList(lendItemQueryWrapper);
            for (LendItem lendItem : lendItems) {
                // 修改投资人账户余额和冻结金额
                String investBindCode = userInfoService.getBindCodeById(lendItem.getInvestUserId());
                userAccountMapper.updateAccount(investBindCode, lendItem.getInvestAmount().negate(), new BigDecimal("0"));

                // 生成投资人交易流水
                transFlowService.saveTransFlow(new TransFlowBO(LendNoUtils.getTransNo(), investBindCode, voteAmt, TransTypeEnum.INVEST_UNLOCK, "放款解锁"));
            }

            // 还款和生成回款计划
            System.out.println("生成还款和回款计划");
            repaymentPlan(lend);
        }
    }

    private Map<String, Object> putParams(Lend lend) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);
        paramMap.put("agentProjectCode", lend.getLendNo());//标的编号
        String agentBillNo = LendNoUtils.getLoanNo();//放款编号
        paramMap.put("agentBillNo", agentBillNo);

        //平台收益，放款扣除，借款人借款实际金额=借款金额-平台收益
        //月年化
        BigDecimal monthRate = lend.getServiceRate().divide(new BigDecimal(12), 8, BigDecimal.ROUND_DOWN);
        //平台实际收益 = 已投金额 * 月年化 * 标的期数
        BigDecimal realAmount = lend.getInvestAmount().multiply(monthRate).multiply(new BigDecimal(lend.getPeriod()));

        paramMap.put("mchFee", realAmount); //商户手续费(平台实际收益)
        paramMap.put("timestamp", RequestHelper.getTimestamp());
        String sign = RequestHelper.getSign(paramMap);
        paramMap.put("sign", sign);
        return paramMap;
    }

    /**
     * 生成还款计划
     *
     * @param lend
     */
    private void repaymentPlan(Lend lend) {
        System.out.println("还款计划");
        // 获得还款期数
        System.out.println("通过lend获得还款期数");
        Integer period = lend.getPeriod();

        // 根据标的id查询投资人的投资记录（集合）lend_item
        System.out.println("根据标的id，查询投资人记录集合");
        Long lendId = lend.getId();
        QueryWrapper<LendItem> lendItemQueryWrapper = new QueryWrapper<>();
        lendItemQueryWrapper.eq("lend_id", lendId);
        List<LendItem> lendItems = lendItemMapper.selectList(lendItemQueryWrapper);//当前标的投资人集合1

        for (Integer i = 1; i <= period; i++) {
            // 循环还款期数，生成lend_return还款计划
            System.out.println("循环生成还款计划");
            System.out.println("在期数循环基础之上，循环投资人记录集合");
            LendReturn lendReturn = new LendReturn();
            lendReturn.setCurrentPeriod(i);
            lendReturn.setLendId(lendId);
            lendReturn.setOverdue(false);
            lendReturn.setOverdueTotal(new BigDecimal("0"));
            lendReturn.setLendYearRate(lend.getLendYearRate());
            lendReturn.setStatus(0);
            lendReturn.setAmount(lend.getAmount());
            lendReturn.setBaseAmount(lend.getAmount());
            lendReturn.setBorrowInfoId(lend.getBorrowInfoId());
            lendReturn.setCreateTime(LocalDateTime.now());
            lendReturn.setReturnMethod(lend.getReturnMethod());
            lendReturn.setUserId(lend.getUserId());

            lendReturnMapper.insert(lendReturn);

            // 在循环里，生成回款记录
            BigDecimal currentInterestTotal = new BigDecimal("0");
            BigDecimal currentPrincipalTotal = new BigDecimal("0");
            for (LendItem lendItem : lendItems) {
                Map<String, BigDecimal> lendReturnPIMap = new HashMap<>();
                lendReturnPIMap = returnInvest(lendReturn, lend, i, lendItem);//返回当期回款计划的总本息
                BigDecimal currentInterest = lendReturnPIMap.get("currentInterest");
                BigDecimal currentPrincipal = lendReturnPIMap.get("currentPrincipal");

                currentInterestTotal = currentInterestTotal.add(currentInterest);
                currentPrincipalTotal = currentPrincipalTotal.add(currentPrincipal);
            }
            //更新lend_return还款计划，将本金利息总和更新进去
            System.out.println("循环更新还款计划");
            lendReturn.setTotal(currentPrincipalTotal.add(currentInterestTotal));
            lendReturn.setInterest(currentInterestTotal);
            lendReturn.setPrincipal(currentPrincipalTotal);
            lendReturn.setFee(lend.getServiceRate().multiply(lendReturn.getTotal()));
            lendReturnMapper.updateById(lendReturn);
        }
    }

    /**
     * 生成回款计划
     *
     * @param 投资金额
     * @param 利率
     * @param 期数
     * @return
     */
    private Map<String, BigDecimal> returnInvest(LendReturn lendReturn, Lend lend, Integer i, LendItem lendItem) {
        //声明返回还款的本金和利息
        Map<String, BigDecimal> lendReturnPIMap = new HashMap<>();

        //声明还款方式
        Integer returnMethod = lend.getReturnMethod();

        System.out.println("调用工具类，根据参数，生成回款计划");
        LendItemReturn lendItemReturn = new LendItemReturn();

        Map<Integer, BigDecimal> interestMap = new HashMap<>();
        Map<Integer, BigDecimal> princialMap = new HashMap<>();
        //计算收益
        if (returnMethod.intValue() == ReturnMethodEnum.ONE.getMethod()) {
            interestMap = Amount1Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            princialMap = Amount1Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.TWO.getMethod()) {
            interestMap = Amount2Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            princialMap = Amount2Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.THREE.getMethod()) {
            interestMap = Amount3Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            princialMap = Amount3Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }
        if (returnMethod.intValue() == ReturnMethodEnum.FOUR.getMethod()) {
            interestMap = Amount4Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            princialMap = Amount4Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }

        BigDecimal currentInterest = interestMap.get(i);//投资人回款本期利息
        BigDecimal currentPrincipal = princialMap.get(i);//投资人回款本期本金
        BigDecimal currentTotal = currentInterest.add(currentPrincipal);//本息

        lendItemReturn.setInterest(currentInterest);
        lendItemReturn.setPrincipal(currentPrincipal);
        lendItemReturn.setLendId(lend.getId());
        lendItemReturn.setLendItemId(lendItem.getId());
        lendItemReturn.setLendReturnId(lendReturn.getId());
        lendItemReturn.setCreateTime(LocalDateTime.now());
        lendItemReturn.setCurrentPeriod(i);
        lendItemReturn.setFee(lend.getServiceRate().multiply(currentTotal));
        lendItemReturn.setInvestAmount(lendItem.getInvestAmount());
        lendItemReturn.setInvestUserId(lendItem.getInvestUserId());
        lendItemReturn.setLendYearRate(lend.getLendYearRate());
        lendItemReturn.setOverdue(false);
        lendItemReturn.setReturnMethod(lend.getReturnMethod());
        lendItemReturn.setStatus(0);
        lendItemReturn.setTotal(currentTotal);

        lendReturnPIMap.put("currentInterest", currentInterest);
        lendReturnPIMap.put("currentPrincipal", currentPrincipal);
        lendItemReturnMapper.insert(lendItemReturn);

        return lendReturnPIMap;
    }
}
